package com.zongtui.fourinone.delegate;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class DelegateHandle implements InvocationHandler
{
	private Class[] bs;
	private DelegateHandle(Class[] bs)
	{
		this.bs = bs;
	}
	
	public static Object bind(Class[] as, Class[] bs)
	{
		return Proxy.newProxyInstance(as[0].getClassLoader(), as, new DelegateHandle(bs));
	}
	
	public static <I> I bind(Class<I> a, Class b)
	{
		return (I)bind(new Class[]{a}, new Class[]{b});
	}
	
	public static <I> I bind(Class<I> a, Class[] bs)
	{
		return (I)bind(new Class[]{a}, bs);
	}

	/*
	public static <I> I bind(Class<I>[] a, Class b)
	{
		return (I)Proxy.newProxyInstance(a[0].getClassLoader(), a, new DelegateHandle(b));//new Class[]
	}
	*/
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
	{
		Object result = null;
		//System.out.println("A:"+proxy.getClass().getSuperclass().getName());
		//System.out.println("A:"+proxy.getClass().getInterfaces()[0]);
		Method mbegin=null,mimpl=null,mend=null;

        for (Class b : bs) {
            Method[] bms = b.getMethods();
            for (Method bm : bms) {
                boolean anflag = bm.isAnnotationPresent(Delegate.class);
                if (anflag) {
                    Delegate dl = bm.getAnnotation(Delegate.class);
                    //System.out.println("dl.interfaceName():"+dl.interfaceName());
                    Class dlifl = Class.forName(dl.interfaceName());
                    if (dlifl.isAssignableFrom(proxy.getClass()) && dl.methodName().equals(method.getName()) && Arrays.equals(method.getParameterTypes(), bm.getParameterTypes()) && method.getReturnType().equals(bm.getReturnType())) {
                        DelegatePolicy dp = dl.policy();
                        if (dp == DelegatePolicy.Begin)
                            mbegin = bm;
                        else if (dp == DelegatePolicy.Implements)
                            mimpl = bm;
                        else if (dp == DelegatePolicy.End)
                            mend = bm;
                    }
                }
            }
        }
		//System.out.println("mimpl111111:"+mimpl);
		if(mimpl!=null)
		{
			if(mbegin!=null)
				mbegin.invoke(mbegin.getDeclaringClass().newInstance(), args);
			//System.out.println("11111111:"+mimpl.getDeclaringClass());
			result = mimpl.invoke(mimpl.getDeclaringClass().newInstance(), args);
			if(mend!=null)
				mend.invoke(mend.getDeclaringClass().newInstance(), args);
		}

		//result = bms[i].invoke(b.newInstance(), args);
		/*
		if(method.getName().equals("getStr"))
			result = (Object)ClientMain.getStrUtil((String)args[0]);
		else if(method.getName().equals("getSomething"))
			result = method.invoke(new ClientMain(), args);
		//System.out.println("end invoke");
		*/
		return result;
	}

}